package com.sinosoft.flow.web;

import com.sinosoft.flow.service.MyProcessModelService;
import com.sinosoft.flow.utils.CommUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.common.engine.impl.javax.el.ELException;
import org.flowable.common.engine.impl.util.IoUtil;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author: njz
 * @Description:
 * @Date: create in 2022/2/11 11:06
 */

@RequestMapping("/api/process-model")
@RestController
@Api("流程模型练习")
public class ProcessModelController {

    @Resource
    private MyProcessModelService myProcessModelService;

    @Resource
    private IdentityService identityService;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private TaskService taskService;

    @Resource
    HistoryService historyService;

    @Resource
    RepositoryService repositoryService;



    @PutMapping("/deploy/{modelId}")
    @ApiOperation("部署流程")
    public ResponseEntity<String> deployProcessModel(@PathVariable String modelId){
        return ResponseEntity.ok(myProcessModelService.deployProcessModel(modelId));
    }

    @PutMapping("/start")
    @ApiOperation("测试开启流程实例")
    public String startProcess(@RequestParam String modelId, @RequestParam String businessKey){

        // 设置发起人
        identityService.setAuthenticatedUserId("admin");

        //设置条件参数
        Map<String, Object> varMap = new HashMap<>(8);
        //写入数据权限部门(其他条件参数也一样, 只要流程执行中涉及到的自定义参数, 都需要写入该Map之中)
        varMap.put("departmentId", "dept_test");

        ProcessInstance processInstance;
        try {
            //deploy.getDeployModelId() 为之前流程部署时返回的流程模板ID, varMap为上文创建的流程变量集合对象
            //processInstance = runtimeService.startProcessInstanceById(modelId, businessKey, varMap);
            processInstance = runtimeService.startProcessInstanceByKey(modelId,businessKey,varMap);
            //返回启动后的流程实例ID
            return processInstance.getProcessInstanceId();
        } catch (Exception e) {
            //捕捉EL表达式中抛出的异常
            if (e.getCause() instanceof ELException && e.getCause().getCause() instanceof RuntimeException) {
                throw new RuntimeException(e.getCause().getCause().getMessage());
            }
//            log.info("[FlowApiServiceImpl].[startFlow] ------> Business System Startup Process, Start, params = {}", JSON.toJSONString(params));
//            log.error("[FlowApiServiceImpl].[startFlow] ------> Business System Startup Process, Error, e:", e);
            throw new RuntimeException("启动流程异常:" + e.getMessage());
        }
    }

    @GetMapping("/getTasks")
    @ApiOperation("测试获取待办任务列表")
    public List<Map<String, Object>> getTasks(@RequestParam String userKey){
        try {
            List<Map<String, Object>> listMap = new ArrayList<>();
            List<Task> tasks = taskService.createTaskQuery().taskAssignee(userKey).list();
            //返回启动后的流程实例ID
            String[] ps = { "owner", "processInstanceId", "processDefinitionId", "suspensionState", "formKey", "priority", "executionId",
                    "taskDefinitionKey" , "subTaskCount" , "createTime" , "name" , "isCountEnabled" , "variableCount" , "assignee" ,
                    "identityLinkCount" , "category"};
            for (Task pd : tasks) {
                Map<String, Object> map = CommUtil.obj2map(pd, ps);
                listMap.add(map);
            }
            return listMap;
        } catch (Exception e) {
            throw new RuntimeException("获取任务列表异常:" + e.getMessage());
        }
    }


    @PutMapping("/completeTask")
    @ApiOperation("测试获取待办任务列表")
    public String complateProcess(@RequestParam String taskId){
        try {
            taskService.complete(taskId);
            return "办理成功！";
        } catch (Exception e) {
            throw new RuntimeException("任务办理异常:" + e.getMessage());
        }
    }

    @RequestMapping("/flowDiagram")
    @ApiOperation("获取流程图")
    public void flowDiagram(@RequestParam String businessKey, HttpServletResponse response) throws Exception{

        ProcessInstance pi = runtimeService
                .createProcessInstanceQuery()
                .processInstanceBusinessKey(businessKey)
                .singleResult();
      //  ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        //流程走完的不显示图
        if (pi == null) {
            return;
        }

        String processId = pi.getProcessInstanceId();
        List<HistoricActivityInstance> historyProcess = getHistoryProcess(processId);
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        for (HistoricActivityInstance hi : historyProcess) {
            String activityType = hi.getActivityType();
            if (activityType.equals("sequenceFlow") || activityType.equals("exclusiveGateway")) {
                flows.add(hi.getActivityId());
            } else if (activityType.equals("userTask") || activityType.equals("startEvent")) {
                activityIds.add(hi.getActivityId());
            }
        }
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processId).list();
        for (Task task : tasks) {
            activityIds.add(task.getTaskDefinitionKey());
        }
        ProcessEngineConfiguration engConf = processEngine().getProcessEngineConfiguration();
        //定义流程画布生成器
        ProcessDiagramGenerator processDiagramGenerator = engConf.getProcessDiagramGenerator();
        InputStream in = processDiagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engConf.getActivityFontName(), engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, true);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = response.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }

    /**
     * 任务历史
     *
     * @param processId 部署id
     */
    public List<HistoricActivityInstance> getHistoryProcess(String processId) {
        List<HistoricActivityInstance> list = historyService // 历史相关Service
                .createHistoricActivityInstanceQuery() // 创建历史活动实例查询
                .processInstanceId(processId) // 执行流程实例id
                .finished()
                .list();
        return list;
    }

    public ProcessEngine processEngine() {
        return ProcessEngines.getDefaultProcessEngine();
    }

}
